package org.apache.maven.plugins.mergeproperties;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.PropertyResourceBundle;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;


/**
 * This Mojo merges all properties files into one file.
 *
 * 
 * @goal merge
 */
public class MergeMojo extends AbstractMojo {


	/**
	 * List of merges to done
	 * @parameter
	 * @required
	 * 
	 */
	private Merge[] merges;

	
	
	/**
	 * If we need to prefix each properties by fileName
	 * 
	 * @parameter default-value="false" 
	 * 
	 */
	private boolean prefixByFileName;
	
	
	/**
	 * used only if prefixByName=true
	 * The separator after the file name prefixprefix  
	 * @parameter default-value="."
	 */	
	private String prefixSeparator;

	
	

	public void execute() throws MojoExecutionException, MojoFailureException {

		getLog().info("Starting merging properties files ...");
		
		for(Merge m : merges) {
			executeMerge(m);
		}
		
		getLog().info("End of merge.");
	}





	private void executeMerge(Merge m) throws MojoExecutionException, MojoFailureException {
		try {
			File propertiesFolder = m.getPropertiesFolder();
			File targetFile       = m.getTargetFile();

			getLog().debug("propertiesFolder=" + propertiesFolder.getAbsolutePath());


			if(!propertiesFolder.isDirectory())
				throw new MojoExecutionException("propertiesFolder need to be a valid folder!");


			if (targetFile.getParent().equals(propertiesFolder.getAbsolutePath())){
				throw new MojoExecutionException("targetFile and propertiesFolder can't be in the same folder!");
			}


			// find all properties files to merge
			List<File> filesToMerge = getPropertiesFiles(propertiesFolder);

			PropertiesConfiguration propertiesMerges = new PropertiesConfiguration();
			propertiesMerges.setEncoding("UTF-8");
			propertiesMerges.setDelimiterParsingDisabled(true);
		

			for (File f : filesToMerge) {
				getLog().info("Processing file : " + f.getName());
				
				// check content
				if (m.getChecks() != null && m.getChecks().length > 0)
					checkContent(f, m);

				// merge properties
				if (isPrefixByFileName()){
					mergeWithPrefix(m, propertiesMerges, f);
					
				} else {
					propertiesMerges.load(f);
				}
			}

			// adding comment and save
			propertiesMerges.setHeader("Generated " + new Date());
			propertiesMerges.save(m.getTargetFile());

		} catch (ConfigurationException e) {
			throw new MojoFailureException(e.getMessage(), e);
		}
	}





	/**
	 * Merge properties adding a prefix to each ridden property
	 * @param merge the input merge operation
	 * @param propMerges the resust of merging operation
	 * @param file the properties to add to merging operation
	 * @throws ConfigurationException if problem
	 */
	private void mergeWithPrefix(Merge merge, PropertiesConfiguration propMerges, File file) throws ConfigurationException {
		
		PropertiesConfiguration current = new PropertiesConfiguration();
		current.setEncoding("UTF-8");
		current.setDelimiterParsingDisabled(true);
		current.load(file);				
		
		String prefix = file.getName().substring(0, file.getName().lastIndexOf("."));
		
		for(String key : current.getLayout().getKeys())
			propMerges.addProperty(prefix + getPrefixSeparator() + key, current.getString(key));
		
	}



	/**
	 * To check all properties files with 
	 * @param propertyFile the property file to check
	 * @throws MojoExecutionException if invalid content
	 */
	private void checkContent(File propertyFile, Merge m) throws  MojoFailureException, MojoExecutionException{				
		try {
			// pattern compilation			
			PropertyResourceBundle rb = new PropertyResourceBundle(new FileReader(propertyFile));

			for (String key : rb.keySet()) {
				String value = rb.getString(key);
				m.checkAllPattern(getLog(), propertyFile.getName(), key,  value);


			}	
		} catch (FileNotFoundException e) {
			throw new MojoExecutionException(e.getMessage(), e);
		} catch (IOException e) {
			throw new MojoExecutionException(e.getMessage(), e);
		}

	}




	/**
	 * Collect properties files in source directory
	 * @param propertiesFolder
	 * @return list of properties files
	 */
	private List<File> getPropertiesFiles(File propertiesFolder) {
		File[] files = propertiesFolder.listFiles();


		// collect properties files in source directory
		List<File> filesToMerge = new ArrayList<File>();
		for (File f : files){
			if (f.getName().endsWith(".properties"))
				filesToMerge.add(f);
		}
		return filesToMerge;
	}





	public boolean isPrefixByFileName() {
		return prefixByFileName;
	}



	public void setPrefixByFileName(boolean prefixByFileName) {
		this.prefixByFileName = prefixByFileName;
	}


	public String getPrefixSeparator() {
		return prefixSeparator;
	}





	public void setPrefixSeparator(String prefixSeparator) {
		this.prefixSeparator = prefixSeparator;
	}



}
